package dao

import (
	"errors"
	controller "fitness/internal/controller/query"
	"fitness/internal/entity"
	"fitness/internal/entity/system"
	"fitness/pkg/utils"
	"fmt"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"strconv"
	"strings"
)

type SysRoleDao struct {
	DB           *gorm.DB
	UserRolesDao *SysUserRolesDao
	Log          *zap.Logger
}

func NewSysRoleDao(db *gorm.DB, userRolesDao *SysUserRolesDao, logger *zap.Logger) *SysRoleDao {
	return &SysRoleDao{
		DB:           db,
		UserRolesDao: userRolesDao,
		Log:          logger,
	}
}

// Option 查询角色信息
func (sysRoleDao *SysRoleDao) Option(tenantQuery controller.TenantQuery) []utils.Option[uint64] {
	var options []utils.Option[uint64]
	var sysRoles []system.SysRole
	tx := sysRoleDao.DB.Select("id,name")
	if tenantQuery.UserType != nil {
		tx = tx.Where("user_type = ?", *tenantQuery.UserType)
	}
	tx.Find(&sysRoles)
	for _, role := range sysRoles {
		var option utils.Option[uint64]
		option.Label = role.Name
		option.Value = *role.ID
		options = append(options, option)
	}
	return options
}

// 分页获取数据
func (sysRoleDao *SysRoleDao) GetRolePage(queryParams controller.TenantPageQuery) (utils.Page[system.SysRole], error) {
	page := *queryParams.PageQuery.PageNum      // 当前页码
	pageSize := *queryParams.PageQuery.PageSize // 每页数据量
	// 计算偏移量
	offset := (page - 1) * pageSize
	var roles []system.SysRole
	var res utils.Page[system.SysRole]
	db := sysRoleDao.DB.Model(&system.SysRole{})
	if queryParams.TenantQuery.UserType != nil {
		db.Where("user_type = ?", *queryParams.TenantQuery.UserType)
	}
	if queryParams.PageQuery.Keywords != nil && *queryParams.PageQuery.Keywords != "" {
		db.Where("code like ? or name like ?", "%"+*queryParams.PageQuery.Keywords+"%", "%"+*queryParams.PageQuery.Keywords+"%")
	}
	// 获取总记录数要在分页上面
	var totalRecords int64
	err := db.Count(&totalRecords).Error
	if err != nil {
		return res, err
	}
	err = db.Offset(int(offset)).Limit(int(pageSize)).Find(&roles).Error
	if err != nil {
		return res, err
	}
	res.List = roles
	res.Total = totalRecords
	return res, nil
}

// 根据id查询角色
func (sysRoleDao *SysRoleDao) GetRoleForm(id uint64) (system.RoleForm, error) {
	var role system.SysRole
	err := sysRoleDao.DB.Model(&system.SysRole{}).Where("id = ?", id).First(&role).Error
	var roleForm system.RoleForm
	if err != nil {
		return roleForm, err
	}
	roleForm.ID = *role.ID
	roleForm.Name = role.Name
	roleForm.Code = role.Code
	roleForm.Sort = role.Sort
	roleForm.Status = role.Status
	roleForm.UserType = &role.UserType
	roleForm.DataScope = role.DataScope
	return roleForm, nil
}

// 保存或修改角色
func (sysRoleDao *SysRoleDao) SaveOrUpdateRole(form system.RoleForm) (id uint64, err error) {
	id, err = sysRoleDao.SaveOrUpdateRoleWithDB(sysRoleDao.DB, form)
	return
}

// 用于事务
func (sysRoleDao *SysRoleDao) SaveOrUpdateRoleWithDB(DB *gorm.DB, form system.RoleForm) (uint64, error) {
	// 编辑角色时，判断角色是否存在
	var oldRole system.SysRole
	if form.ID != 0 {
		result := DB.Model(&system.SysRole{}).Where("id = ? ", form.ID).First(&oldRole)
		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
			return 0, errors.New("角色不存在")
		} else if result.Error != nil {
			return 0, result.Error
		}
	}
	var count int64
	db := DB.Model(&system.SysRole{})
	if form.ID != 0 {
		db.Where("id <> ?", form.ID)
	}
	err := db.Where("(code = ? or name =?) and user_type = ?",
		form.Code, form.Name, form.UserType).Count(&count).Error
	if err != nil {
		return 0, err
	}
	if count > 0 {
		sysRoleDao.Log.Error("角色名称或角色编码已存在，请修改后重试！")
		return 0, errors.New("角色名称或角色编码已存在，请修改后重试！")
	}
	var deleted = uint8(0)
	sysRole := system.SysRole{
		Model: entity.Model{
			ID:        &form.ID,
			IsDeleted: &deleted,
		},
		Name:      form.Name,
		Code:      form.Code,
		Sort:      form.Sort,
		Status:    form.Status,
		UserType:  *form.UserType,
		DataScope: form.DataScope,
	}

	if form.ID == 0 {
		err := DB.Model(&system.SysRole{}).Save(&sysRole).Error
		if err != nil {
			return 0, err
		}
	} else {
		err := DB.Model(&system.SysRole{}).Select("name", "code", "sort", "status", "data_scope").
			Where("id = ?", form.ID).
			Updates(&sysRole).Error
		if err != nil {
			return 0, err
		}
	}
	return *sysRole.ID, nil
}

// 根据id获取数据
func (sysRoleDao *SysRoleDao) GetRoleById(id uint64) (system.SysRole, error) {
	var sysRole system.SysRole
	result := sysRoleDao.DB.Model(&system.SysRole{}).Where("id = ?", id).First(&sysRole)
	if errors.Is(result.Error, gorm.ErrRecordNotFound) {
		return sysRole, errors.New("角色不存在")
	} else if result.Error != nil {
		return sysRole, result.Error
	}
	return sysRole, nil
}

func (sysRoleDao *SysRoleDao) DeleteRoles(ids string) (bool, error) {
	err := sysRoleDao.DB.Transaction(func(tx *gorm.DB) error {
		if ids == "" {
			return errors.New("至少需要一个参数")
		}
		split := strings.Split(ids, ",")
		var list []uint64
		for _, val := range split {
			end, _ := strconv.ParseUint(val, 10, 64)
			list = append(list, end)
		}
		for _, roleId := range list {
			sysRole, err := sysRoleDao.GetRoleById(roleId)
			if err != nil {
				return err
			}
			count, err := sysRoleDao.UserRolesDao.HasAssignedUsers(roleId)
			if err != nil {
				return err
			}
			if count {
				return errors.New("角色【" + sysRole.Name + "】已分配用户，请先解除关联后删除")
			}
			err = sysRoleDao.DB.Delete(&system.SysRole{}, "id = ?", roleId).Error
			if err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		return false, err
	} else {
		return true, nil
	}
}

// 权限分配
func (sysRoleDao *SysRoleDao) GetRoleMenuIds(id string) ([]uint64, error) {
	sql := `SELECT
            rm.menu_id
        FROM
            sys_role_menu rm
                INNER JOIN sys_menu m ON rm.menu_id = m.id
        WHERE
            rm.role_id =` + id
	var ids []uint64
	err := sysRoleDao.DB.Raw(sql).Find(&ids).Error
	if err != nil {
		sysRoleDao.Log.Error("查询权限分配报错", zap.Error(err))
		return ids, err
	}
	return ids, nil
}

func (sysRoleDao *SysRoleDao) AssignMenusToRole(idStr string, ids []uint64) (b bool, e error) {
	db := sysRoleDao.DB.Begin()
	defer func() {
		if r := recover(); r != nil {
			db.Rollback() // 捕获panic，确保回滚
			fmt.Println("Recovered in safeCall", r)
			b = false
			e = errors.New("执行报错")
		}
	}()
	var sysRole system.SysRole
	err := db.Model(&system.SysRole{}).Where("id = ?", idStr).Find(&sysRole).Error
	if err != nil {
		db.Rollback()
		sysRoleDao.Log.Error("查询报错", zap.Error(err))
		return false, errors.New("角色不存在")
	}
	err = db.Delete(&system.SysRoleMenu{}, "role_id = ?", idStr).Error
	if err != nil {
		db.Rollback()
		sysRoleDao.Log.Error("删除角色菜单失败", zap.Error(err))
		return false, errors.New("删除角色菜单失败")
	}
	//批量创建角色菜单
	var roleMenus []system.SysRoleMenu
	for _, id := range ids {
		menu := system.SysRoleMenu{
			RoleId: *sysRole.ID,
			MenuId: id,
		}
		roleMenus = append(roleMenus, menu)
	}
	err = db.Model(&system.SysRoleMenu{}).CreateInBatches(&roleMenus, 100).Error
	if err != nil {
		db.Rollback()
		sysRoleDao.Log.Error("批量保存角色菜单失败", zap.Error(err))
		return false, errors.New("批量保存角色菜单失败")
	}
	db.Commit()
	return true, nil
}
